home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / exec31.arc / EXEC.C < prev    next >
C/C++ Source or Header  |  1991-08-25  |  14KB  |  556 lines

  1. /*
  2.    --- Version 3.1 91-08-17 23:06 ---
  3.  
  4.    EXEC.C: EXEC function with memory swap - Prepare parameters.
  5.  
  6.    Public domain software by
  7.  
  8.         Thomas Wagner
  9.         Ferrari electronic GmbH
  10.         Beusselstrasse 27
  11.         D-1000 Berlin 21
  12.         Germany
  13. */
  14.  
  15. #include "compat.h"
  16. #include "exec.h"
  17. #include "checkpat.h"
  18. #include <bios.h>
  19.  
  20. /*>e
  21.    Set REDIRECT to 1 to support redirection, else to 0.
  22.    CAUTION: The definition in 'spawn.asm' must match this definition!!
  23. <*/
  24. /*>d
  25.    Setzen Sie REDIRECT auf 1 um Dateiumleitung zu untertützen, sonst auf 0.
  26.    ACHTUNG: Die Definition in 'spawn.asm' muß mit dieser Definition 
  27.    übereinstimmen!!
  28. <*/
  29.  
  30.  
  31. #define REDIRECT  1
  32.  
  33. #define SWAP_FILENAME "$$AAAAAA.AAA" 
  34.  
  35. /*e internal flags for prep_swap */
  36. /*d interne Flags für prep_swap */
  37.  
  38. #define CREAT_TEMP      0x0080
  39. #define DONT_SWAP_ENV   0x4000
  40.  
  41. #define ERR_COMSPEC     -7
  42. #define ERR_NOMEM       -8
  43.  
  44. /*e local variables */
  45. /*d Lokale Variablen */
  46.  
  47. static char drive [MAXDRIVE], dir [MAXDIR];
  48. static char name [MAXFILE], ext [MAXEXT];
  49. static char cmdpath [MAXPATH] = "";
  50. static char cmdpars [80] = "";
  51.  
  52.  
  53. #ifdef __cplusplus
  54. extern "C" int
  55. #else
  56. extern int _cdecl
  57. #endif
  58. do_spawn (int swapping,     /*e swap if non-0 */
  59.                             /*d Auslagern wenn nicht 0 */
  60.           char *xeqfn,      /*e file to execute */
  61.                             /*d auszuführende Datei */
  62.           char *cmdtail,    /*e command tail string */
  63.                             /*d Kommandozeile */
  64.           unsigned envlen,  /*e environment length */
  65.                             /*d Länge Umgebungsvariablen */
  66.           char *envp        /*e environment pointer */
  67.                             /*d Zeiger auf Umgebungsvariablen */
  68. #if (REDIRECT)
  69.           ,char *rstdin,    /*e redirection file names */
  70.                             /*d Umleitungs-Dateinamen */
  71.           char *rstdout,
  72.           char *rstderr
  73. #endif
  74.           );
  75.  
  76. #ifdef __cplusplus
  77. extern "C" int
  78. #else
  79. extern int _cdecl
  80. #endif
  81. prep_swap (int method,      /*e swap method */
  82.                             /*d Auslagerungsmethode */
  83.            char *swapfn);   /*e swap file name and/or path */
  84.                             /*d Auslagerungsdateiname und/oder Pfad */
  85.  
  86. #ifdef __cplusplus
  87. extern "C" int
  88. #else
  89. extern int _cdecl
  90. #endif
  91. exists (char *fname);
  92.  
  93. /* --------------------------------------------------------------------- */
  94.  
  95. /*>e Try '.COM', '.EXE', and '.BAT' on current filename, modify 
  96.    filename if found. <*/
  97. /*>d '.COM', '.EXE' und '.BAT' mit dem aktuellen Dateinamen versuchen,
  98.    Dateinamen modifizieren wenn gefunden. <*/
  99.  
  100. int tryext (char *fn)
  101. {
  102.    char *ext;
  103.  
  104.    ext = strchr (fn, '\0');
  105.    strcpy (ext, ".COM");
  106.    if (exists (fn))
  107.       return 1;
  108.    strcpy (ext, ".EXE");
  109.    if (exists (fn))
  110.       return 1;
  111.    strcpy (ext, ".BAT");
  112.    if (exists (fn))
  113.       return 2;
  114.    *ext = 0;
  115.    return 0;
  116. }
  117.  
  118. /*>e Try to find the file 'fn' in the current path. Modifies the filename
  119.    accordingly. <*/
  120. /*>d Versuchen die Datei 'fn' im aktuellen Pfad zu finden. Der Dateiname
  121.    wird entsprechend modifiziert. <*/
  122.  
  123. int findfile (char *fn)
  124. {
  125.    char *path, *penv;
  126.    char *prfx;
  127.    int found, check, hasext;
  128.  
  129.    if (!*fn)
  130.       return (cmdpath [0]) ? 3 : ERR_COMSPEC;
  131.  
  132.    check = checkpath (fn, drive, dir, name, ext, fn);
  133.    if (check < 0)
  134.       return check;
  135.  
  136.    if ((check & HAS_WILD) || !(check & HAS_FNAME))
  137.       return ERR_FNAME;
  138.  
  139.    hasext = (check & HAS_EXT) ? ((!stricmp (ext, ".bat")) ? 2 : 1) : 0;
  140.  
  141.    if (hasext)
  142.       {
  143.       if (check & FILE_EXISTS)
  144.          found = hasext;
  145.       else
  146.          found = 0;
  147.       }
  148.    else
  149.       found = tryext (fn);
  150.  
  151.    if (found || (check & (HAS_PATH | HAS_DRIVE)))
  152.       return found;
  153.  
  154.    penv = getenv ("PATH");
  155.    if (!penv)
  156.       return 0;
  157.    path = (char *)malloc (strlen (penv) + 1);
  158.    if (path == NULL)
  159.       return ERR_NOMEM;
  160.  
  161.    strcpy (path, penv);
  162.    prfx = strtok (path, ";");
  163.  
  164.    while (!found && prfx != NULL)
  165.       {
  166.       while (isspace (*prfx))
  167.          prfx++;
  168.       if (*prfx)
  169.          {
  170.          strcpy (fn, prfx);
  171.          prfx = strchr (fn, '\0');
  172.          prfx--;
  173.          if (*prfx != '\\' && *prfx != '/' && *prfx != ':')
  174.             {
  175.             *++prfx = '\\';
  176.             }
  177.          prfx++;
  178.          strcpy (prfx, name);
  179.          strcat (prfx, ext);
  180.          check = checkpath (fn, drive, dir, name, ext, fn);
  181.          if (check > 0 && (check & HAS_FNAME))
  182.             {
  183.             if (hasext)
  184.                {
  185.                if (check & FILE_EXISTS)
  186.                   found = hasext;
  187.                }
  188.             else
  189.                found = tryext (fn);
  190.             }
  191.          }
  192.       prfx = strtok (NULL, ";");
  193.       }
  194.    free (path);
  195.    return found;
  196. }
  197.  
  198.  
  199. /*>e 
  200.    Get name and path of the command processor via the COMSPEC 
  201.    environmnt variable. Any parameters after the program name
  202.    are copied and inserted into the command line.
  203. <*/
  204. /*>d
  205.    Namen und Pfad des Kommandoprozessors über die COMSPEC-Umgebungs-
  206.    Variable bestimmen. Parameter nach dem Programmnamen werden kopiert
  207.    und in die Kommandozeile eingefügt.
  208. <*/
  209.  
  210. static void getcmdpath (void)
  211. {
  212.    char *pcmd;
  213.    int found = 0;
  214.  
  215.    if (cmdpath [0])
  216.       return;
  217.    pcmd = getenv ("COMSPEC");
  218.    if (pcmd)
  219.       {
  220.       strcpy (cmdpath, pcmd);
  221.       pcmd = cmdpath;
  222.       while (isspace (*pcmd))
  223.          pcmd++;
  224.       if (NULL != (pcmd = strpbrk (pcmd, ";,=+/\"[]|<> \t")))
  225.          {
  226.          while (isspace (*pcmd))
  227.             *pcmd++ = 0;
  228.          if (strlen (pcmd) >= 79)
  229.             pcmd [79] = 0;
  230.          strcpy (cmdpars, pcmd);
  231.          strcat (cmdpars, " ");
  232.          }
  233.       found = findfile (cmdpath);
  234.       }
  235.    if (!found)
  236.       {
  237.       cmdpars [0] = 0;
  238.       strcpy (cmdpath, "COMMAND.COM");
  239.       found = findfile (cmdpath);
  240.       if (!found)
  241.          cmdpath [0] = 0;
  242.       }
  243. }
  244.  
  245.  
  246. /*>e
  247.    tempdir: Set temporary file path.
  248.             Read "TMP/TEMP" environment. If empty or invalid, clear path.
  249.             If TEMP is drive or drive+backslash only, return TEMP.
  250.             Otherwise check if given path is a valid directory.
  251.             If so, add a backslash, else clear path.
  252. <*/
  253. /*>d
  254.    tempdir: Pfad für temporäre Datei setzen.
  255.             Die Umgebungsvariable "TMP" oder "TEMP" wird gelesen. Ist
  256.             keine der beiden vorhanden, oder sind sie ungültig, wird
  257.             der Pfad gelöscht.
  258.             Besteht TMP/TEMP nur aus Laufwerksbuchstaben, oder aus
  259.             Laufwerk und Backslash, liefern TEMP.
  260.             Sonst prüfen ob der Pfad gültig ist, und einen Backslash
  261.             anfügen.
  262. <*/
  263.  
  264. int tempdir (char *outfn)
  265. {
  266.    int i, res;
  267.    char *stmp [4];
  268.  
  269.    stmp [0] = getenv ("TMP");
  270.    stmp [1] = getenv ("TEMP");
  271.    stmp [2] = ".\\";
  272.    stmp [3] = "\\";
  273.  
  274.    for (i = 0; i < 4; i++)
  275.       if (stmp [i])
  276.          {
  277.          strcpy (outfn, stmp [i]);
  278.          res = checkpath (outfn, drive, dir, name, ext, outfn);
  279.          if (res > 0 && (res & IS_DIR) && !(res & IS_READ_ONLY))
  280.             return 1;
  281.          }
  282.    return 0;
  283. }
  284.  
  285.  
  286. #if (REDIRECT)
  287.  
  288. int redirect (char *par, char **rstdin, char **rstdout, char **rstderr)
  289. {
  290.    char ch, sav;
  291.    char *fn, *fnp;
  292.    int app;
  293.  
  294.    do
  295.       {
  296.       app = 0;
  297.       ch = *par;
  298.       *par++ = 0;
  299.       if (ch != '<')
  300.          {
  301.          if (*par == '&')
  302.             {
  303.             ch = '&';
  304.             par++;
  305.             }
  306.          if (*par == '>')
  307.             {
  308.             app = 1;
  309.             par++;
  310.             }
  311.          }
  312.  
  313.       while (isspace (*par))
  314.          par++;
  315.       fn = par;
  316.       if ((fnp = strpbrk (par, ";,=+/\"[]|<> \t")) != NULL)
  317.          par = fnp;
  318.       else
  319.          par = strchr (par, '\0');
  320.       sav = *par;
  321.       *par = 0;
  322.  
  323.       if (!strlen (fn))
  324.          return 0;
  325.       fnp = (char *)malloc (strlen (fn) + app + 1);
  326.       if (fnp == NULL)
  327.          return 0;
  328.       if (app)
  329.          {
  330.          strcpy (fnp, ">");
  331.          strcat (fnp, fn);
  332.          }
  333.       else
  334.          strcpy (fnp, fn);
  335.  
  336.       switch (ch)
  337.          {
  338.          case '<':   if (*rstdin != NULL)
  339.                         return 0;
  340.                      *rstdin = fnp;
  341.                      break;
  342.          case '>':   if (*rstdout != NULL)
  343.                         return 0;
  344.                      *rstdout = fnp;
  345.                      break;
  346.          case '&':   if (*rstderr != NULL)
  347.                         return 0;
  348.                      *rstderr = fnp;
  349.                      break;
  350.          }
  351.  
  352.       *par = sav;
  353.       while (isspace (*par))
  354.          par++;
  355.       }
  356.    while (*par == '>' || *par == '<');
  357.  
  358.    return 1;
  359. }
  360.  
  361. #endif
  362.  
  363.  
  364. int do_exec (char *exfn, char *epars, int spwn, unsigned needed, char **envp)
  365. {
  366.    static char swapfn [MAXPATH];
  367.    static char execfn [MAXPATH];
  368.    unsigned avail;
  369.    union REGS regs;
  370.    unsigned envlen;
  371.    int rc;
  372.    int idx;
  373.    char **env;
  374.    char *ep, *envptr, *envbuf;
  375.    char *progpars;
  376.    int swapping;
  377. #if (REDIRECT)
  378.    char *rstdin = NULL, *rstdout = NULL, *rstderr = NULL;
  379. #endif
  380.  
  381.    strcpy (execfn, exfn);
  382.    getcmdpath ();
  383.  
  384.    /*e First, check if the file to execute exists. */
  385.    /*d Zunächst prüfen ob die auszuführende Datei existiert. */
  386.  
  387.    if ((rc = findfile (execfn)) <= 0)
  388.       return RC_NOFILE | -rc;
  389.  
  390.    if (rc > 1)   /* COMMAND.COM or Batch file */
  391.       {
  392.       if (!cmdpath [0])
  393.          return RC_NOFILE | -ERR_COMSPEC;
  394.  
  395.       idx = (rc == 2) ? strlen (execfn) + 5 : 1;
  396.       progpars = (char *)malloc (strlen (epars) + strlen (cmdpars) + idx);
  397.       if (progpars == NULL)
  398.          return RC_NOFILE | -ERR_NOMEM;
  399.       strcpy (progpars, cmdpars);
  400.       if (rc == 2)
  401.          {
  402.          strcat (progpars, "/c ");
  403.          strcat (progpars, execfn);
  404.          strcat (progpars, " ");
  405.          }
  406.       strcat (progpars, epars);
  407.       strcpy (execfn, cmdpath);
  408.       }
  409.    else
  410.       {
  411.       progpars = (char *)malloc (strlen (epars) + 1);
  412.       if (progpars == NULL)
  413.          return RC_NOFILE | -ERR_NOMEM;
  414.       strcpy (progpars, epars);
  415.       }
  416.  
  417. #if (REDIRECT)
  418.    if ((ep = strpbrk (progpars, "<>")) != NULL)
  419.       if (!redirect (ep, &rstdin, &rstdout, &rstderr))
  420.          {
  421.          rc = RC_REDIRERR;
  422.          goto exit;
  423.          }
  424. #endif
  425.  
  426.    /*e Now create a copy of the environment if the user wants it. */
  427.    /*d Nun eine Kopie der Umgebungsvariablen anlegen wenn angefordert. */
  428.  
  429.    envlen = 0;
  430.    envptr = NULL;
  431.  
  432.    if (envp != NULL)
  433.       for (env = envp; *env != NULL; env++)
  434.          envlen += strlen (*env) + 1;
  435.  
  436.    if (envlen)
  437.       {
  438.       /*e round up to paragraph, and alloc another paragraph leeway */
  439.       /*d Auf Paragraphengrenze runden, plus einen Paragraphen zur Sicherheit */
  440.       envlen = (envlen + 32) & 0xfff0;
  441.       envbuf = (char *)malloc (envlen);
  442.       if (envbuf == NULL)
  443.          {
  444.          rc = RC_ENVERR;
  445.          goto exit;
  446.          }
  447.  
  448.       /*e align to paragraph */
  449.       /*d Auf Paragraphengrenze adjustieren */
  450.       envptr = envbuf;
  451.       if (FP_OFF (envptr) & 0x0f)
  452.          envptr += 16 - (FP_OFF (envptr) & 0x0f);
  453.       ep = envptr;
  454.  
  455.       for (env = envp; *env != NULL; env++)
  456.          {
  457.          ep = stpcpy (ep, *env) + 1;
  458.          }
  459.       *ep = 0;
  460.       }
  461.  
  462.    if (!spwn)
  463.       swapping = -1;
  464.    else
  465.       {
  466.       /*e Determine amount of free memory */
  467.       /*d Freien Speicherbereich feststellen */
  468.  
  469.       regs.x.ax = 0x4800;
  470.       regs.x.bx = 0xffff;
  471.       intdos (®s, ®s);
  472.       avail = regs.x.bx;
  473.  
  474.       /*e No swapping if available memory > needed */
  475.       /*d Keine Auslagerung wenn freier Speicher > benötigter */
  476.  
  477.       if (needed < avail)
  478.          swapping = 0;
  479.       else
  480.          {
  481.          /*>e Swapping necessary, use 'TMP' or 'TEMP' environment variable
  482.            to determine swap file path if defined. <*/
  483.          /*>d Auslagerung notwendig, 'TMP' oder 'TEMP' Umgebungsvariable
  484.             verwenden um Auslagerungsdateipfad festzulegen. <*/
  485.  
  486.          swapping = spwn;
  487.          if (spwn & USE_FILE)
  488.             {
  489.             if (!tempdir (swapfn))
  490.                {
  491.                spwn &= ~USE_FILE;
  492.                swapping = spwn;
  493.                }
  494.             else if (OS_MAJOR >= 3)
  495.                swapping |= CREAT_TEMP;
  496.             else
  497.                {
  498.                strcat (swapfn, SWAP_FILENAME);
  499.                idx = strlen (swapfn) - 1;
  500.                while (exists (swapfn))
  501.                   {
  502.                   if (swapfn [idx] == 'Z')
  503.                      idx--;
  504.                   if (swapfn [idx] == '.')
  505.                      idx--;
  506.                   swapfn [idx]++;
  507.                   }
  508.                }
  509.             }
  510.          }
  511.       }
  512.  
  513.    /*e All set up, ready to go. */
  514.    /*d Alles vorbereitet, jetzt kann's losgehen. */
  515.  
  516.    if (swapping > 0)
  517.       {
  518.       if (!envlen)
  519.          swapping |= DONT_SWAP_ENV;
  520.  
  521.       rc = prep_swap (swapping, swapfn);
  522.       if (rc < 0)
  523.          rc = RC_PREPERR | -rc;
  524.       else
  525.          rc = 0;
  526.       }
  527.    else
  528.       rc = 0;
  529.  
  530.    if (!rc)
  531. #if (REDIRECT)
  532.       rc = do_spawn (swapping, execfn, progpars, envlen, envptr, rstdin, rstdout, rstderr);
  533. #else
  534.       rc = do_spawn (swapping, execfn, progpars, envlen, envptr);
  535. #endif
  536.  
  537.    /*e Free the environment buffer if it was allocated. */
  538.    /*d Den Umgebungsvariablenblock freigeben falls er alloziert wurde. */
  539.  
  540. exit:
  541.    free (progpars);
  542. #if (REDIRECT)
  543.    if (rstdin)
  544.       free (rstdin);
  545.    if (rstdout)
  546.       free (rstdout);
  547.    if (rstderr)
  548.       free (rstderr);
  549. #endif
  550.    if (envlen)
  551.       free (envbuf);
  552.  
  553.    return rc;
  554. }
  555.  
  556.